// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.core.raknet;

import fmod.fmod.FMODManager;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.concurrent.Semaphore;
import se.krka.kahlua.vm.JavaFunction;
import se.krka.kahlua.vm.KahluaTable;
import se.krka.kahlua.vm.LuaCallFrame;
import se.krka.kahlua.vm.Platform;
import zombie.characters.IsoPlayer;
import zombie.core.Core;
import zombie.core.network.ByteBufferWriter;
import zombie.debug.DebugLog;
import zombie.debug.LogSeverity;
import zombie.input.GameKeyboard;
import zombie.inventory.InventoryItem;
import zombie.inventory.types.Radio;
import zombie.iso.IsoCell;
import zombie.iso.IsoGridSquare;
import zombie.iso.IsoObject;
import zombie.iso.IsoUtils;
import zombie.iso.objects.IsoRadio;
import zombie.iso.objects.IsoWorldInventoryObject;
import zombie.network.FakeClientManager;
import zombie.network.GameClient;
import zombie.network.GameServer;
import zombie.network.MPStatistics;
import zombie.network.PacketTypes;
import zombie.network.ServerOptions;
import zombie.radio.devices.DeviceData;
import zombie.vehicles.VehiclePart;

public class VoiceManager {
    private static final int FMOD_SOUND_MODE = FMODManager.FMOD_OPENUSER | FMODManager.FMOD_LOOP_NORMAL | FMODManager.FMOD_CREATESTREAM;
    public static final int modePPT = 1;
    public static final int modeVAD = 2;
    public static final int modeMute = 3;
    public static final int VADModeQuality = 1;
    public static final int VADModeLowBitrate = 2;
    public static final int VADModeAggressive = 3;
    public static final int VADModeVeryAggressive = 4;
    public static final int AGCModeAdaptiveAnalog = 1;
    public static final int AGCModeAdaptiveDigital = 2;
    public static final int AGCModeFixedDigital = 3;
    private static final int bufferSize = 192;
    private static final int complexity = 1;
    private static boolean serverVOIPEnable = true;
    private static int sampleRate = 16000;
    private static int period = 300;
    private static int buffering = 8000;
    private static float minDistance;
    private static float maxDistance;
    private static boolean is3D = false;
    private boolean isEnable = true;
    private boolean isModeVAD = false;
    private boolean isModePPT = false;
    private int vadMode = 3;
    private int agcMode = 2;
    private int volumeMic;
    private int volumePlayers;
    public static boolean VoipDisabled = false;
    private boolean isServer;
    private static fmod.FMODSoundBuffer FMODReceiveBuffer;
    private int FMODVoiceRecordDriverId;
    private long FMODChannelGroup = 0L;
    private long FMODRecordSound = 0L;
    private Semaphore recDevSemaphore;
    private boolean initialiseRecDev = false;
    private boolean initialisedRecDev = false;
    private long indicatorIsVoice = 0L;
    private Thread thread;
    private boolean bQuit;
    private long timeLast;
    private boolean isDebug = false;
    private boolean isDebugLoopback = false;
    private boolean isDebugLoopbackLong = false;
    public static VoiceManager instance = new VoiceManager();
    byte[] buf = new byte[192];
    private final Object notifier = new Object();
    private boolean bIsClient = false;
    private boolean bTestingMicrophone = false;
    private long testingMicrophoneMS = 0L;
    private final Long recBuf_Current_read = new Long(0L);
    private static long timestamp = 0L;

    public static VoiceManager getInstance() {
        return instance;
    }

    public void DeinitRecSound() {
        this.initialisedRecDev = false;
        if (this.FMODRecordSound != 0L) {
            fmod.javafmod.FMOD_RecordSound_Release(this.FMODRecordSound);
            this.FMODRecordSound = 0L;
        }

        FMODReceiveBuffer = null;
    }

    public void ResetRecSound() {
        if (this.initialisedRecDev && this.FMODRecordSound != 0L) {
            int int0 = fmod.javafmod.FMOD_System_RecordStop(this.FMODVoiceRecordDriverId);
            if (int0 != fmod.FMOD_RESULT.FMOD_OK.ordinal()) {
                DebugLog.Voice.warn("FMOD_System_RecordStop result=%d", int0);
            }
        }

        this.DeinitRecSound();
        this.FMODRecordSound = fmod.javafmod.FMOD_System_CreateRecordSound(
            (long)this.FMODVoiceRecordDriverId,
            (long)(FMODManager.FMOD_2D | FMODManager.FMOD_OPENUSER | FMODManager.FMOD_SOFTWARE),
            (long)FMODManager.FMOD_SOUND_FORMAT_PCM16,
            (long)sampleRate,
            this.agcMode
        );
        if (this.FMODRecordSound == 0L) {
            DebugLog.Voice.warn("FMOD_System_CreateSound result=%d", this.FMODRecordSound);
        }

        fmod.javafmod.FMOD_System_SetRecordVolume(1L - Math.round(Math.pow(1.4, (double)(11 - this.volumeMic))));
        if (this.initialiseRecDev) {
            int int1 = fmod.javafmod.FMOD_System_RecordStart(this.FMODVoiceRecordDriverId, this.FMODRecordSound, true);
            if (int1 != fmod.FMOD_RESULT.FMOD_OK.ordinal()) {
                DebugLog.Voice.warn("FMOD_System_RecordStart result=%d", int1);
            }
        }

        fmod.javafmod.FMOD_System_SetVADMode(this.vadMode - 1);
        FMODReceiveBuffer = new fmod.FMODSoundBuffer(this.FMODRecordSound);
        this.initialisedRecDev = true;
    }

    public void VoiceRestartClient(boolean _isEnable) {
        if (GameClient.connection != null) {
            if (_isEnable) {
                this.loadConfig();
                this.VoiceConnectReq(GameClient.connection.getConnectedGUID());
            } else {
                this.threadSafeCode(this::DeinitRecSound);
                this.VoiceConnectClose(GameClient.connection.getConnectedGUID());
                this.loadConfig();
            }
        } else {
            this.loadConfig();
            if (_isEnable) {
                this.InitRecDeviceForTest();
            } else {
                this.threadSafeCode(this::DeinitRecSound);
            }
        }
    }

    void VoiceInitClient() {
        this.isServer = false;
        this.recDevSemaphore = new Semaphore(1);
        FMODReceiveBuffer = null;
        RakVoice.RVInit(192);
        RakVoice.SetComplexity(1);
    }

    void VoiceInitServer(boolean boolean0, int int1, int int0, int int2, int int3, double double1, double double0, boolean boolean1) {
        this.isServer = true;
        if (!(int0 == 2 | int0 == 5 | int0 == 10 | int0 == 20 | int0 == 40 | int0 == 60)) {
            DebugLog.Voice.error("Invalid period=%d", int0);
        } else if (!(int1 == 8000 | int1 == 16000 | int1 == 24000)) {
            DebugLog.Voice.error("Invalid sample rate=%d", int1);
        } else if (int2 < 0 | int2 > 10) {
            DebugLog.Voice.error("Invalid quality=%d", int2);
        } else if (int3 < 0 | int3 > 32000) {
            DebugLog.Voice.error("Invalid buffering=%d", int3);
        } else {
            sampleRate = int1;
            RakVoice.RVInitServer(boolean0, int1, int0, int2, int3, (float)double1, (float)double0, boolean1);
        }
    }

    void VoiceConnectAccept(long _long) {
        if (this.isEnable) {
            DebugLog.Voice.debugln("uuid=%x", _long);
        }
    }

    void InitRecDeviceForTest() {
        this.threadSafeCode(this::ResetRecSound);
    }

    void VoiceOpenChannelReply(long long0, ByteBuffer byteBuffer) {
        if (this.isEnable) {
            DebugLog.Voice.debugln("uuid=%d", long0);
            if (this.isServer) {
                return;
            }

            try {
                if (GameClient.bClient) {
                    serverVOIPEnable = byteBuffer.getInt() != 0;
                    sampleRate = byteBuffer.getInt();
                    period = byteBuffer.getInt();
                    byteBuffer.getInt();
                    buffering = byteBuffer.getInt();
                    minDistance = byteBuffer.getFloat();
                    maxDistance = byteBuffer.getFloat();
                    is3D = byteBuffer.getInt() != 0;
                } else {
                    serverVOIPEnable = RakVoice.GetServerVOIPEnable();
                    sampleRate = RakVoice.GetSampleRate();
                    period = RakVoice.GetSendFramePeriod();
                    buffering = RakVoice.GetBuffering();
                    minDistance = RakVoice.GetMinDistance();
                    maxDistance = RakVoice.GetMaxDistance();
                    is3D = RakVoice.GetIs3D();
                }
            } catch (Exception exception) {
                DebugLog.Voice.printException(exception, "RakVoice params set failed", LogSeverity.Error);
                return;
            }

            DebugLog.Voice
                .debugln(
                    "enabled=%b, sample-rate=%d, period=%d, complexity=%d, buffering=%d, is3D=%b", serverVOIPEnable, sampleRate, period, 1, buffering, is3D
                );

            try {
                this.recDevSemaphore.acquire();
            } catch (InterruptedException interruptedException) {
                interruptedException.printStackTrace();
            }

            int _int = is3D ? FMODManager.FMOD_3D | FMOD_SOUND_MODE : FMOD_SOUND_MODE;

            for (VoiceManagerData voiceManagerData : VoiceManagerData.data) {
                if (voiceManagerData.userplaysound != 0L) {
                    fmod.javafmod.FMOD_Sound_SetMode(voiceManagerData.userplaysound, _int);
                }
            }

            long long1 = fmod.javafmod.FMOD_System_SetRawPlayBufferingPeriod((long)buffering);
            if (long1 != (long)fmod.FMOD_RESULT.FMOD_OK.ordinal()) {
                DebugLog.Voice.warn("FMOD_System_SetRawPlayBufferingPeriod result=%d", long1);
            }

            this.ResetRecSound();
            this.recDevSemaphore.release();
            if (this.isDebug) {
                VoiceDebug.createAndShowGui();
            }
        }
    }

    public void VoiceConnectReq(long uuid) {
        if (this.isEnable) {
            DebugLog.Voice.debugln("uuid=%x", uuid);
            VoiceManagerData.data.clear();
            RakVoice.RequestVoiceChannel(uuid);
        }
    }

    public void VoiceConnectClose(long uuid) {
        if (this.isEnable) {
            DebugLog.Voice.debugln("uuid=%x", uuid);
            RakVoice.CloseVoiceChannel(uuid);
        }
    }

    public void setMode(int mode) {
        if (mode == 3) {
            this.isModeVAD = false;
            this.isModePPT = false;
        } else if (mode == 1) {
            this.isModeVAD = false;
            this.isModePPT = true;
        } else if (mode == 2) {
            this.isModeVAD = true;
            this.isModePPT = false;
        }
    }

    public void setVADMode(int mode) {
        if (!(mode < 1 | mode > 4)) {
            this.vadMode = mode;
            if (this.initialisedRecDev) {
                this.threadSafeCode(() -> fmod.javafmod.FMOD_System_SetVADMode(this.vadMode - 1));
            }
        }
    }

    public void setAGCMode(int mode) {
        if (!(mode < 1 | mode > 3)) {
            this.agcMode = mode;
            if (this.initialisedRecDev) {
                this.threadSafeCode(this::ResetRecSound);
            }
        }
    }

    public void setVolumePlayers(int volume) {
        if (!(volume < 0 | volume > 11)) {
            if (volume <= 10) {
                this.volumePlayers = volume;
            } else {
                this.volumePlayers = 12;
            }

            if (this.initialisedRecDev) {
                ArrayList arrayList = VoiceManagerData.data;

                for (int _int = 0; _int < arrayList.size(); _int++) {
                    VoiceManagerData voiceManagerData = (VoiceManagerData)arrayList.get(_int);
                    if (voiceManagerData != null && voiceManagerData.userplaychannel != 0L) {
                        fmod.javafmod.FMOD_Channel_SetVolume(voiceManagerData.userplaychannel, (float)((double)this.volumePlayers * 0.2));
                    }
                }
            }
        }
    }

    public void setVolumeMic(int volume) {
        if (!(volume < 0 | volume > 11)) {
            if (volume <= 10) {
                this.volumeMic = volume;
            } else {
                this.volumeMic = 12;
            }

            if (this.initialisedRecDev) {
                this.threadSafeCode(() -> fmod.javafmod.FMOD_System_SetRecordVolume(1L - Math.round(Math.pow(1.4, (double)(11 - this.volumeMic)))));
            }
        }
    }

    public static void playerSetMute(String username) {
        ArrayList arrayList = GameClient.instance.getPlayers();

        for (int _int = 0; _int < arrayList.size(); _int++) {
            IsoPlayer isoPlayer = (IsoPlayer)arrayList.get(_int);
            if (username.equals(isoPlayer.username)) {
                VoiceManagerData voiceManagerData = VoiceManagerData.get(isoPlayer.OnlineID);
                voiceManagerData.userplaymute = !voiceManagerData.userplaymute;
                isoPlayer.isVoiceMute = voiceManagerData.userplaymute;
                break;
            }
        }
    }

    public static boolean playerGetMute(String username) {
        ArrayList arrayList = GameClient.instance.getPlayers();

        for (int _int = 0; _int < arrayList.size(); _int++) {
            IsoPlayer isoPlayer = (IsoPlayer)arrayList.get(_int);
            if (username.equals(isoPlayer.username)) {
                return VoiceManagerData.get(isoPlayer.OnlineID).userplaymute;
            }
        }

        return true;
    }

    public void LuaRegister(Platform platform, KahluaTable kahluaTable1) {
        KahluaTable kahluaTable0 = platform.newTable();
        kahluaTable0.rawset("playerSetMute", new JavaFunction() {
            public int call(LuaCallFrame luaCallFrame, int var2) {
                Object object = luaCallFrame.get(1);
                VoiceManager.playerSetMute((String)object);
                return 1;
            }
        });
        kahluaTable0.rawset("playerGetMute", new JavaFunction() {
            public int call(LuaCallFrame luaCallFrame, int var2) {
                Object object = luaCallFrame.get(1);
                luaCallFrame.push(VoiceManager.playerGetMute((String)object));
                return 1;
            }
        });
        kahluaTable0.rawset("RecordDevices", new JavaFunction() {
            public int call(LuaCallFrame luaCallFrame, int var2) {
                if (!Core.SoundDisabled && !VoiceManager.VoipDisabled) {
                    int int0 = fmod.javafmod.FMOD_System_GetRecordNumDrivers();
                    KahluaTable kahluaTable0 = luaCallFrame.getPlatform().newTable();

                    for (int int1 = 0; int1 < int0; int1++) {
                        fmod.FMOD_DriverInfo fMOD_DriverInfo = new fmod.FMOD_DriverInfo();
                        fmod.javafmod.FMOD_System_GetRecordDriverInfo(int1, fMOD_DriverInfo);
                        kahluaTable0.rawset(int1 + 1, fMOD_DriverInfo.name);
                    }

                    luaCallFrame.push(kahluaTable0);
                    return 1;
                } else {
                    KahluaTable kahluaTable1 = luaCallFrame.getPlatform().newTable();
                    luaCallFrame.push(kahluaTable1);
                    return 1;
                }
            }
        });
        kahluaTable1.rawset("VoiceManager", kahluaTable0);
    }

    private void setUserPlaySound(long _long, float _float) {
        _float = IsoUtils.clamp(_float * IsoUtils.lerp((float)this.volumePlayers, 0.0F, 12.0F), 0.0F, 1.0F);
        fmod.javafmod.FMOD_Channel_SetVolume(_long, _float);
    }

    private long getUserPlaySound(short _short) {
        VoiceManagerData voiceManagerData = VoiceManagerData.get(_short);
        if (voiceManagerData.userplaychannel == 0L) {
            voiceManagerData.userplaysound = 0L;
            int _int = is3D ? FMODManager.FMOD_3D | FMOD_SOUND_MODE : FMOD_SOUND_MODE;
            voiceManagerData.userplaysound = fmod.javafmod.FMOD_System_CreateRAWPlaySound(
                (long)_int, (long)FMODManager.FMOD_SOUND_FORMAT_PCM16, (long)sampleRate
            );
            if (voiceManagerData.userplaysound == 0L) {
                DebugLog.Voice.warn("FMOD_System_CreateSound result=%d", voiceManagerData.userplaysound);
            }

            voiceManagerData.userplaychannel = fmod.javafmod.FMOD_System_PlaySound(voiceManagerData.userplaysound, false);
            if (voiceManagerData.userplaychannel == 0L) {
                DebugLog.Voice.warn("FMOD_System_PlaySound result=%d", voiceManagerData.userplaychannel);
            }

            fmod.javafmod.FMOD_Channel_SetVolume(voiceManagerData.userplaychannel, (float)((double)this.volumePlayers * 0.2));
            if (is3D) {
                fmod.javafmod.FMOD_Channel_Set3DMinMaxDistance(voiceManagerData.userplaychannel, minDistance / 2.0F, maxDistance);
            }

            fmod.javafmod.FMOD_Channel_SetChannelGroup(voiceManagerData.userplaychannel, this.FMODChannelGroup);
        }

        return voiceManagerData.userplaysound;
    }

    public void InitVMClient() {
        if (!Core.SoundDisabled && !VoipDisabled) {
            int _int = fmod.javafmod.FMOD_System_GetRecordNumDrivers();
            this.FMODVoiceRecordDriverId = Core.getInstance().getOptionVoiceRecordDevice() - 1;
            if (this.FMODVoiceRecordDriverId < 0 && _int > 0) {
                Core.getInstance().setOptionVoiceRecordDevice(1);
                this.FMODVoiceRecordDriverId = Core.getInstance().getOptionVoiceRecordDevice() - 1;
            }

            if (_int < 1) {
                DebugLog.Voice.debugln("Microphone not found");
                this.initialiseRecDev = false;
            } else if (this.FMODVoiceRecordDriverId < 0 | this.FMODVoiceRecordDriverId >= _int) {
                DebugLog.Voice.warn("Invalid record device");
                this.initialiseRecDev = false;
            } else {
                this.initialiseRecDev = true;
            }

            this.isEnable = Core.getInstance().getOptionVoiceEnable();
            this.setMode(Core.getInstance().getOptionVoiceMode());
            this.vadMode = Core.getInstance().getOptionVoiceVADMode();
            this.volumeMic = Core.getInstance().getOptionVoiceVolumeMic();
            this.volumePlayers = Core.getInstance().getOptionVoiceVolumePlayers();
            this.FMODChannelGroup = fmod.javafmod.FMOD_System_CreateChannelGroup("VOIP");
            this.VoiceInitClient();
            this.FMODRecordSound = 0L;
            if (this.isEnable) {
                this.InitRecDeviceForTest();
            }

            if (this.isDebug) {
                VoiceDebug.createAndShowGui();
            }

            this.timeLast = System.currentTimeMillis();
            this.bQuit = false;
            this.thread = new Thread() {
                public void run() {
                    while (!VoiceManager.this.bQuit) {
                        try {
                            VoiceManager.this.UpdateVMClient();
                            sleep((long)(VoiceManager.period / 2));
                        } catch (Exception exception) {
                            exception.printStackTrace();
                        }
                    }
                }
            };
            this.thread.setName("VoiceManagerClient");
            this.thread.start();
        } else {
            this.isEnable = false;
            this.initialiseRecDev = false;
            this.initialisedRecDev = false;
            DebugLog.Voice.debugln("Disabled");
        }
    }

    public void loadConfig() {
        this.isEnable = Core.getInstance().getOptionVoiceEnable();
        this.setMode(Core.getInstance().getOptionVoiceMode());
        this.vadMode = Core.getInstance().getOptionVoiceVADMode();
        this.volumeMic = Core.getInstance().getOptionVoiceVolumeMic();
        this.volumePlayers = Core.getInstance().getOptionVoiceVolumePlayers();
    }

    public void UpdateRecordDevice() {
        if (this.initialisedRecDev) {
            this.threadSafeCode(this::UpdateRecordDeviceInternal);
        }
    }

    private void UpdateRecordDeviceInternal() {
        int _int = fmod.javafmod.FMOD_System_RecordStop(this.FMODVoiceRecordDriverId);
        if (_int != fmod.FMOD_RESULT.FMOD_OK.ordinal()) {
            DebugLog.Voice.warn("FMOD_System_RecordStop result=%d", _int);
        }

        this.FMODVoiceRecordDriverId = Core.getInstance().getOptionVoiceRecordDevice() - 1;
        if (this.FMODVoiceRecordDriverId < 0) {
            DebugLog.Voice.error("No record device found");
        } else {
            _int = fmod.javafmod.FMOD_System_RecordStart(this.FMODVoiceRecordDriverId, this.FMODRecordSound, true);
            if (_int != fmod.FMOD_RESULT.FMOD_OK.ordinal()) {
                DebugLog.Voice.warn("FMOD_System_RecordStart result=%d", _int);
            }
        }
    }

    public void DeinitVMClient() {
        if (this.thread != null) {
            this.bQuit = true;
            synchronized (this.notifier) {
                this.notifier.notify();
            }

            while (this.thread.isAlive()) {
                try {
                    Thread.sleep(10L);
                } catch (InterruptedException interruptedException) {
                }
            }

            this.thread = null;
        }

        this.DeinitRecSound();
        ArrayList arrayList = VoiceManagerData.data;

        for (int _int = 0; _int < arrayList.size(); _int++) {
            VoiceManagerData voiceManagerData = (VoiceManagerData)arrayList.get(_int);
            if (voiceManagerData.userplaychannel != 0L) {
                fmod.javafmod.FMOD_Channel_Stop(voiceManagerData.userplaychannel);
            }

            if (voiceManagerData.userplaysound != 0L) {
                fmod.javafmod.FMOD_RAWPlaySound_Release(voiceManagerData.userplaysound);
                voiceManagerData.userplaysound = 0L;
            }
        }

        VoiceManagerData.data.clear();
    }

    public void setTestingMicrophone(boolean testing) {
        if (testing) {
            this.testingMicrophoneMS = System.currentTimeMillis();
        }

        if (testing != this.bTestingMicrophone) {
            this.bTestingMicrophone = testing;
            this.notifyThread();
        }
    }

    public void notifyThread() {
        synchronized (this.notifier) {
            this.notifier.notify();
        }
    }

    public void update() {
        if (!GameServer.bServer) {
            if (this.bTestingMicrophone) {
                long _long = System.currentTimeMillis();
                if (_long - this.testingMicrophoneMS > 1000L) {
                    this.setTestingMicrophone(false);
                }
            }

            if ((!GameClient.bClient || GameClient.connection == null) && !FakeClientManager.isVOIPEnabled()) {
                if (this.bIsClient) {
                    this.bIsClient = false;
                    this.notifyThread();
                }
            } else if (!this.bIsClient) {
                this.bIsClient = true;
                this.notifyThread();
            }
        }
    }

    private float getCanHearAllVolume(float _float) {
        return _float > minDistance ? IsoUtils.clamp(1.0F - IsoUtils.lerp(_float, minDistance, maxDistance), 0.2F, 1.0F) : 1.0F;
    }

    private void threadSafeCode(Runnable runnable) {
        while (true) {
            try {
                this.recDevSemaphore.acquire();
            } catch (InterruptedException interruptedException) {
                continue;
            }

            try {
                runnable.run();
            } finally {
                this.recDevSemaphore.release();
            }

            return;
        }
    }

    synchronized void UpdateVMClient() throws InterruptedException {
        while (!this.bQuit && !this.bIsClient && !this.bTestingMicrophone) {
            synchronized (this.notifier) {
                try {
                    this.notifier.wait();
                } catch (InterruptedException interruptedException) {
                }
            }
        }

        if (serverVOIPEnable) {
            if (IsoPlayer.getInstance() != null) {
                IsoPlayer.getInstance().isSpeek = System.currentTimeMillis() - this.indicatorIsVoice <= 300L;
            }

            if (this.initialiseRecDev) {
                this.recDevSemaphore.acquire();
                fmod.javafmod.FMOD_System_GetRecordPosition(this.FMODVoiceRecordDriverId, this.recBuf_Current_read);
                if (FMODReceiveBuffer != null) {
                    while (FMODReceiveBuffer.pull(this.recBuf_Current_read)) {
                        if (IsoPlayer.getInstance() != null && GameClient.connection != null || FakeClientManager.isVOIPEnabled()) {
                            if (is3D && IsoPlayer.getInstance().isDead()) {
                                continue;
                            }

                            if (this.isModePPT) {
                                if (GameKeyboard.isKeyDown(Core.getInstance().getKey("Enable voice transmit"))) {
                                    RakVoice.SendFrame(
                                        GameClient.connection.connectedGUID,
                                        (long)IsoPlayer.getInstance().OnlineID,
                                        FMODReceiveBuffer.buf(),
                                        FMODReceiveBuffer.get_size()
                                    );
                                    this.indicatorIsVoice = System.currentTimeMillis();
                                } else if (FakeClientManager.isVOIPEnabled()) {
                                    RakVoice.SendFrame(
                                        FakeClientManager.getConnectedGUID(),
                                        FakeClientManager.getOnlineID(),
                                        FMODReceiveBuffer.buf(),
                                        FMODReceiveBuffer.get_size()
                                    );
                                    this.indicatorIsVoice = System.currentTimeMillis();
                                }
                            }

                            if (this.isModeVAD && FMODReceiveBuffer.get_vad() != 0L) {
                                RakVoice.SendFrame(
                                    GameClient.connection.connectedGUID,
                                    (long)IsoPlayer.getInstance().OnlineID,
                                    FMODReceiveBuffer.buf(),
                                    FMODReceiveBuffer.get_size()
                                );
                                this.indicatorIsVoice = System.currentTimeMillis();
                            }
                        }

                        if (this.isDebug) {
                            if (GameClient.IDToPlayerMap.values().size() > 0) {
                                VoiceDebug.updateGui(null, FMODReceiveBuffer);
                            } else if (this.isDebugLoopback) {
                                VoiceDebug.updateGui(null, FMODReceiveBuffer);
                            } else {
                                VoiceDebug.updateGui(null, FMODReceiveBuffer);
                            }
                        }

                        if (this.isDebugLoopback) {
                            fmod.javafmod.FMOD_System_RAWPlayData(this.getUserPlaySound((short)0), FMODReceiveBuffer.buf(), FMODReceiveBuffer.get_size());
                        }
                    }
                }

                this.recDevSemaphore.release();
            }

            ArrayList arrayList0 = GameClient.instance.getPlayers();
            ArrayList arrayList1 = VoiceManagerData.data;

            for (int int0 = 0; int0 < arrayList1.size(); int0++) {
                VoiceManagerData voiceManagerData0 = (VoiceManagerData)arrayList1.get(int0);
                boolean _boolean = false;

                for (int int1 = 0; int1 < arrayList0.size(); int1++) {
                    IsoPlayer isoPlayer0 = (IsoPlayer)arrayList0.get(int1);
                    if (isoPlayer0.OnlineID == voiceManagerData0.index) {
                        _boolean = true;
                        break;
                    }
                }

                if (this.isDebugLoopback & voiceManagerData0.index == 0) {
                    break;
                }

                if (voiceManagerData0.userplaychannel != 0L & !_boolean) {
                    fmod.javafmod.FMOD_Channel_Stop(voiceManagerData0.userplaychannel);
                    voiceManagerData0.userplaychannel = 0L;
                }
            }

            long _long = System.currentTimeMillis() - this.timeLast;
            if (_long >= (long)period) {
                this.timeLast += _long;
                if (IsoPlayer.getInstance() == null) {
                    return;
                }

                VoiceManagerData.VoiceDataSource voiceDataSource = VoiceManagerData.VoiceDataSource.Unknown;
                int int2 = 0;

                for (IsoPlayer isoPlayer1 : arrayList0) {
                    IsoPlayer isoPlayer2 = IsoPlayer.getInstance();
                    if (isoPlayer1 != isoPlayer2 && isoPlayer1.getOnlineID() != -1) {
                        VoiceManagerData voiceManagerData1 = VoiceManagerData.get(isoPlayer1.getOnlineID());

                        while (RakVoice.ReceiveFrame((long)isoPlayer1.getOnlineID(), this.buf)) {
                            voiceManagerData1.voicetimeout = 10L;
                            if (!voiceManagerData1.userplaymute) {
                                float _float = IsoUtils.DistanceTo(isoPlayer2.getX(), isoPlayer2.getY(), isoPlayer1.getX(), isoPlayer1.getY());
                                if (isoPlayer2.isCanHearAll()) {
                                    fmod.javafmodJNI.FMOD_Channel_Set3DLevel(voiceManagerData1.userplaychannel, 0.0F);
                                    fmod.javafmod.FMOD_Channel_Set3DAttributes(
                                        voiceManagerData1.userplaychannel, isoPlayer2.x, isoPlayer2.y, isoPlayer2.z, 0.0F, 0.0F, 0.0F
                                    );
                                    this.setUserPlaySound(voiceManagerData1.userplaychannel, this.getCanHearAllVolume(_float));
                                    voiceDataSource = VoiceManagerData.VoiceDataSource.Cheat;
                                    int2 = 0;
                                } else {
                                    VoiceManagerData.RadioData radioData = this.checkForNearbyRadios(voiceManagerData1);
                                    if (radioData != null && radioData.deviceData != null) {
                                        fmod.javafmodJNI.FMOD_Channel_Set3DLevel(voiceManagerData1.userplaychannel, 0.0F);
                                        fmod.javafmod.FMOD_Channel_Set3DAttributes(
                                            voiceManagerData1.userplaychannel, isoPlayer2.x, isoPlayer2.y, isoPlayer2.z, 0.0F, 0.0F, 0.0F
                                        );
                                        this.setUserPlaySound(voiceManagerData1.userplaychannel, radioData.deviceData.getDeviceVolume());
                                        radioData.deviceData.doReceiveMPSignal(radioData.lastReceiveDistance);
                                        voiceDataSource = VoiceManagerData.VoiceDataSource.Radio;
                                        int2 = radioData.freq;
                                    } else {
                                        if (radioData == null) {
                                            fmod.javafmodJNI.FMOD_Channel_Set3DLevel(voiceManagerData1.userplaychannel, 0.0F);
                                            fmod.javafmod.FMOD_Channel_Set3DAttributes(
                                                voiceManagerData1.userplaychannel, isoPlayer2.x, isoPlayer2.y, isoPlayer2.z, 0.0F, 0.0F, 0.0F
                                            );
                                            fmod.javafmod.FMOD_Channel_SetVolume(voiceManagerData1.userplaychannel, 0.0F);
                                            voiceDataSource = VoiceManagerData.VoiceDataSource.Unknown;
                                        } else {
                                            if (is3D) {
                                                fmod.javafmodJNI.FMOD_Channel_Set3DLevel(
                                                    voiceManagerData1.userplaychannel, IsoUtils.lerp(_float, 0.0F, minDistance)
                                                );
                                                fmod.javafmod.FMOD_Channel_Set3DAttributes(
                                                    voiceManagerData1.userplaychannel, isoPlayer1.x, isoPlayer1.y, isoPlayer1.z, 0.0F, 0.0F, 0.0F
                                                );
                                            } else {
                                                fmod.javafmodJNI.FMOD_Channel_Set3DLevel(voiceManagerData1.userplaychannel, 0.0F);
                                                fmod.javafmod.FMOD_Channel_Set3DAttributes(
                                                    voiceManagerData1.userplaychannel, isoPlayer2.x, isoPlayer2.y, isoPlayer2.z, 0.0F, 0.0F, 0.0F
                                                );
                                            }

                                            this.setUserPlaySound(
                                                voiceManagerData1.userplaychannel, IsoUtils.smoothstep(maxDistance, minDistance, radioData.lastReceiveDistance)
                                            );
                                            voiceDataSource = VoiceManagerData.VoiceDataSource.Voice;
                                        }

                                        int2 = 0;
                                        if (_float > maxDistance) {
                                            logFrame(isoPlayer2, isoPlayer1, _float);
                                        }
                                    }
                                }

                                fmod.javafmod.FMOD_System_RAWPlayData(this.getUserPlaySound(isoPlayer1.getOnlineID()), this.buf, (long)this.buf.length);
                                if (this.isDebugLoopbackLong) {
                                    RakVoice.SendFrame(GameClient.connection.connectedGUID, (long)isoPlayer2.getOnlineID(), this.buf, (long)this.buf.length);
                                }
                            }
                        }

                        if (voiceManagerData1.voicetimeout == 0L) {
                            isoPlayer1.isSpeek = false;
                        } else {
                            voiceManagerData1.voicetimeout--;
                            isoPlayer1.isSpeek = true;
                        }
                    }
                }

                MPStatistics.setVOIPSource(voiceDataSource, int2);
            }
        }
    }

    private static void logFrame(IsoPlayer isoPlayer1, IsoPlayer isoPlayer0, float _float) {
        long _long = System.currentTimeMillis();
        if (_long > timestamp) {
            timestamp = _long + 5000L;
            DebugLog.Multiplayer
                .warn(
                    String.format(
                        "\"%s\" (%b) received VOIP frame from \"%s\" (%b) at distance=%f",
                        isoPlayer1.getUsername(),
                        isoPlayer1.isCanHearAll(),
                        isoPlayer0.getUsername(),
                        isoPlayer0.isCanHearAll(),
                        _float
                    )
                );
        }
    }

    private VoiceManagerData.RadioData checkForNearbyRadios(VoiceManagerData voiceManagerData1) {
        IsoPlayer isoPlayer = IsoPlayer.getInstance();
        VoiceManagerData voiceManagerData0 = VoiceManagerData.get(isoPlayer.OnlineID);
        if (voiceManagerData0.isCanHearAll) {
            ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0)).lastReceiveDistance = 0.0F;
            return (VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0);
        } else {
            synchronized (voiceManagerData0.radioData) {
                for (int int0 = 1; int0 < voiceManagerData0.radioData.size(); int0++) {
                    synchronized (voiceManagerData1.radioData) {
                        for (int int1 = 1; int1 < voiceManagerData1.radioData.size(); int1++) {
                            if (((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(int0)).freq
                                == ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(int1)).freq) {
                                float float0 = (float)(
                                    ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(int0)).x
                                        - ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(int1)).x
                                );
                                float float1 = (float)(
                                    ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(int0)).y
                                        - ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(int1)).y
                                );
                                ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(int0)).lastReceiveDistance = (float)Math.sqrt(
                                    (double)(float0 * float0 + float1 * float1)
                                );
                                if (((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(int0)).lastReceiveDistance
                                    < ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(int1)).distance) {
                                    return (VoiceManagerData.RadioData)voiceManagerData0.radioData.get(int0);
                                }
                            }
                        }
                    }
                }
            }

            synchronized (voiceManagerData0.radioData) {
                synchronized (voiceManagerData1.radioData) {
                    if (!voiceManagerData1.radioData.isEmpty() && !voiceManagerData0.radioData.isEmpty()) {
                        float float2 = (float)(
                            ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0)).x
                                - ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(0)).x
                        );
                        float float3 = (float)(
                            ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0)).y
                                - ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(0)).y
                        );
                        ((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0)).lastReceiveDistance = (float)Math.sqrt(
                            (double)(float2 * float2 + float3 * float3)
                        );
                        if (((VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0)).lastReceiveDistance
                            < ((VoiceManagerData.RadioData)voiceManagerData1.radioData.get(0)).distance) {
                            return (VoiceManagerData.RadioData)voiceManagerData0.radioData.get(0);
                        }
                    }
                }

                return null;
            }
        }
    }

    public void UpdateChannelsRoaming(UdpConnection connection) {
        IsoPlayer isoPlayer0 = IsoPlayer.getInstance();
        if (isoPlayer0.OnlineID != -1) {
            VoiceManagerData voiceManagerData = VoiceManagerData.get(isoPlayer0.OnlineID);
            boolean _boolean = false;
            synchronized (voiceManagerData.radioData) {
                voiceManagerData.radioData.clear();

                for (int int0 = 0; int0 < IsoPlayer.numPlayers; int0++) {
                    IsoPlayer isoPlayer1 = IsoPlayer.players[int0];
                    if (isoPlayer1 != null) {
                        _boolean |= isoPlayer1.isCanHearAll();
                        voiceManagerData.radioData.add(new VoiceManagerData.RadioData(RakVoice.GetMaxDistance(), isoPlayer1.x, isoPlayer1.y));

                        for (int int1 = 0; int1 < isoPlayer1.getInventory().getItems().size(); int1++) {
                            InventoryItem inventoryItem = (InventoryItem)isoPlayer1.getInventory().getItems().get(int1);
                            if (inventoryItem instanceof Radio) {
                                DeviceData deviceData0 = ((Radio)inventoryItem).getDeviceData();
                                if (deviceData0 != null && deviceData0.getIsTurnedOn()) {
                                    voiceManagerData.radioData.add(new VoiceManagerData.RadioData(deviceData0, isoPlayer1.x, isoPlayer1.y));
                                }
                            }
                        }

                        for (int int2 = (int)isoPlayer1.getX() - 4; (float)int2 < isoPlayer1.getX() + 5.0F; int2++) {
                            for (int int3 = (int)isoPlayer1.getY() - 4; (float)int3 < isoPlayer1.getY() + 5.0F; int3++) {
                                for (int int4 = (int)isoPlayer1.getZ() - 1; (float)int4 < isoPlayer1.getZ() + 1.0F; int4++) {
                                    IsoGridSquare isoGridSquare = IsoCell.getInstance().getGridSquare(int2, int3, int4);
                                    if (isoGridSquare != null) {
                                        if (isoGridSquare.getObjects() != null) {
                                            for (int int5 = 0; int5 < isoGridSquare.getObjects().size(); int5++) {
                                                IsoObject isoObject = isoGridSquare.getObjects().get(int5);
                                                if (isoObject instanceof IsoRadio) {
                                                    DeviceData deviceData1 = ((IsoRadio)isoObject).getDeviceData();
                                                    if (deviceData1 != null && deviceData1.getIsTurnedOn()) {
                                                        voiceManagerData.radioData
                                                            .add(new VoiceManagerData.RadioData(deviceData1, (float)isoGridSquare.x, (float)isoGridSquare.y));
                                                    }
                                                }
                                            }
                                        }

                                        if (isoGridSquare.getWorldObjects() != null) {
                                            for (int int6 = 0; int6 < isoGridSquare.getWorldObjects().size(); int6++) {
                                                IsoWorldInventoryObject isoWorldInventoryObject = (IsoWorldInventoryObject)isoGridSquare.getWorldObjects()
                                                    .get(int6);
                                                if (isoWorldInventoryObject.getItem() != null && isoWorldInventoryObject.getItem() instanceof Radio) {
                                                    DeviceData deviceData2 = ((Radio)isoWorldInventoryObject.getItem()).getDeviceData();
                                                    if (deviceData2 != null && deviceData2.getIsTurnedOn()) {
                                                        voiceManagerData.radioData
                                                            .add(new VoiceManagerData.RadioData(deviceData2, (float)isoGridSquare.x, (float)isoGridSquare.y));
                                                    }
                                                }
                                            }
                                        }

                                        if (isoGridSquare.getVehicleContainer() != null && isoGridSquare == isoGridSquare.getVehicleContainer().getSquare()) {
                                            VehiclePart vehiclePart = isoGridSquare.getVehicleContainer().getPartById("Radio");
                                            if (vehiclePart != null) {
                                                DeviceData deviceData3 = vehiclePart.getDeviceData();
                                                if (deviceData3 != null && deviceData3.getIsTurnedOn()) {
                                                    voiceManagerData.radioData
                                                        .add(new VoiceManagerData.RadioData(deviceData3, (float)isoGridSquare.x, (float)isoGridSquare.y));
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            ByteBufferWriter byteBufferWriter = connection.startPacket();
            PacketTypes.PacketType.SyncRadioData.doPacket(byteBufferWriter);
            byteBufferWriter.putByte((byte)(_boolean ? 1 : 0));
            byteBufferWriter.putInt(voiceManagerData.radioData.size() * 4);

            for (VoiceManagerData.RadioData radioData : voiceManagerData.radioData) {
                byteBufferWriter.putInt(radioData.freq);
                byteBufferWriter.putInt((int)radioData.distance);
                byteBufferWriter.putInt(radioData.x);
                byteBufferWriter.putInt(radioData.y);
            }

            PacketTypes.PacketType.SyncRadioData.send(connection);
        }
    }

    void InitVMServer() {
        this.VoiceInitServer(
            ServerOptions.instance.VoiceEnable.getValue(),
            24000,
            20,
            5,
            8000,
            ServerOptions.instance.VoiceMinDistance.getValue(),
            ServerOptions.instance.VoiceMaxDistance.getValue(),
            ServerOptions.instance.Voice3D.getValue()
        );
    }

    public int getMicVolumeIndicator() {
        return FMODReceiveBuffer == null ? 0 : (int)FMODReceiveBuffer.get_loudness();
    }

    public boolean getMicVolumeError() {
        return FMODReceiveBuffer == null ? true : FMODReceiveBuffer.get_interror();
    }

    public boolean getServerVOIPEnable() {
        return serverVOIPEnable;
    }

    public void VMServerBan(short player_id, boolean is_ban) {
        RakVoice.SetVoiceBan((long)player_id, is_ban);
    }
}
